// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_INPUT_H_
#define CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_INPUT_H_

#include <memory>
#include <string>

#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "media/audio/audio_input_ipc.h"
#include "media/base/audio_parameters.h"

class GURL;

namespace base {
class SingleThreadTaskRunner;
}

namespace media {
class AudioParameters;
}

namespace content {

class PepperAudioInputHost;
class PepperMediaDeviceManager;

// PepperPlatformAudioInput is operated on two threads: the main thread (the
// thread on which objects are created) and the I/O thread. All public methods,
// except the destructor, must be called on the main thread. The notifications
// to the users of this class (i.e. PepperAudioInputHost) are also sent on the
// main thread. Internally, this class sends audio input IPC messages and
// receives media::AudioInputIPCDelegate notifications on the I/O thread.

class PepperPlatformAudioInput
    : public media::AudioInputIPCDelegate,
      public base::RefCountedThreadSafe<PepperPlatformAudioInput> {
public:
    // Factory function, returns NULL on failure. StreamCreated() will be called
    // when the stream is created.
    static PepperPlatformAudioInput* Create(
        int render_frame_id,
        const std::string& device_id,
        const GURL& document_url,
        int sample_rate,
        int frames_per_buffer,
        PepperAudioInputHost* client);

    // Called on main thread.
    void StartCapture();
    void StopCapture();
    // Closes the stream. Make sure to call this before the object is destructed.
    void ShutDown();

    // media::AudioInputIPCDelegate.
    void OnStreamCreated(base::SharedMemoryHandle handle,
        base::SyncSocket::Handle socket_handle,
        int length,
        int total_segments) override;
    void OnError() override;
    void OnIPCClosed() override;

protected:
    ~PepperPlatformAudioInput() override;

private:
    friend class base::RefCountedThreadSafe<PepperPlatformAudioInput>;

    PepperPlatformAudioInput();

    bool Initialize(int render_frame_id,
        const std::string& device_id,
        const GURL& document_url,
        int sample_rate,
        int frames_per_buffer,
        PepperAudioInputHost* client);

    // I/O thread backends to above functions.
    void InitializeOnIOThread(int session_id);
    void StartCaptureOnIOThread();
    void StopCaptureOnIOThread();
    void ShutDownOnIOThread();

    void OnDeviceOpened(int request_id, bool succeeded, const std::string& label);
    void CloseDevice();
    void NotifyStreamCreationFailed();

    // Can return NULL if the RenderFrame referenced by |render_frame_id_| has
    // gone away.
    PepperMediaDeviceManager* GetMediaDeviceManager();

    // The client to notify when the stream is created. THIS MUST ONLY BE
    // ACCESSED ON THE MAIN THREAD.
    PepperAudioInputHost* client_;

    // Used to send/receive IPC. THIS MUST ONLY BE ACCESSED ON THE
    // I/O THREAD.
    std::unique_ptr<media::AudioInputIPC> ipc_;

    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;

    // The frame containing the Pepper widget.
    int render_frame_id_;

    // The unique ID to identify the opened device. THIS MUST ONLY BE ACCESSED ON
    // THE MAIN THREAD.
    std::string label_;

    // Initialized on the main thread and accessed on the I/O thread afterwards.
    media::AudioParameters params_;

    // Whether we have tried to create an audio stream. THIS MUST ONLY BE ACCESSED
    // ON THE I/O THREAD.
    bool create_stream_sent_;

    // Whether we have a pending request to open a device. We have to make sure
    // there isn't any pending request before this object goes away.
    // THIS MUST ONLY BE ACCESSED ON THE MAIN THREAD.
    bool pending_open_device_;
    // THIS MUST ONLY BE ACCESSED ON THE MAIN THREAD.
    int pending_open_device_id_;

    DISALLOW_COPY_AND_ASSIGN(PepperPlatformAudioInput);
};

} // namespace content

#endif // CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_INPUT_H_
